/*!***************************************************
 * @file: func_app.c
 * @brief: 实现好友和通信功能的应用逻辑
 * @author: ITHAO 
 * @date: 2018.12.12
 * @note: 
 ****************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>

#include "func.h"
#include "comm_protocol_core.h"
#include "debug.h"
#include "func_app.h"
#include "app.h"


/**
 * @brief	向好友发送聊天信息  
 * @param	mutexfd--带互斥的socket通信fd
 *          chat_packet--聊天包
 *          聊天包里面需要有
 *          发送者昵称--send_name
 *          发送者账号--send_account
 *          接收者账号--recv_account
 *          消息     --msg
 * @return	-FUNCAPP_PARAM_NULL_ERR     入口参数空
 *          -FUNCAPP_FD_INVALID_ERR     fd无效
 *          -FUNCAPP_SEND_ERR           发送失败
 *          -FUNCAPP_RECV_ERR           接收失败
 * 
 *          TRUE                                发送成功
 *          FUNCAPP_OWNER_ACCOUNT_NOT_EXIST     用户账号不存在
 *          FUNCAPP_FRIEND_ACCOUNT_NOT_EXIST    好友账号不存在
 *          FUNCAPP_SHORT_OF_DATA               缺少发送信息 
 * @note:
 */
int send_msg(struct mutexfd *mutexfd, struct chat_packet chat_packet)
{
    int ret = 0;
    struct comm_core comm;
    time_t timep; 
    pthread_mutex_t *mutex = NULL; 

    if (!mutexfd || !chat_packet.send_name || 
        !chat_packet.send_account || !chat_packet.recv_account ||
        !chat_packet.msg) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (mutexfd->clientfd == -1) {
        DEBUG("SOCKET FD 无效！\r\n");
        return (-FUNCAPP_FD_INVALID_ERR);
    }

    time(&timep);
    chat_packet.send_time = ctime(&timep);
    /*把换行符去掉*/
    chat_packet.send_time[strlen(chat_packet.send_time) - 1] = '\0';
    mutex = &mutexfd->mutex;
    comm_core_init(&comm);
    comm.data.sendfd = mutexfd->clientfd;
    comm.data.recvfd = mutexfd->clientfd;

    comm.data.send_data_packet.cmd_type = CHAT_CMD_TYPE;
    comm.data.send_data_packet.data[0] = (uint8 *)chat_packet.send_account;
    comm.data.send_data_packet.data[1] = (uint8 *)chat_packet.recv_account;
    comm.data.send_data_packet.data[2] = (uint8 *)chat_packet.send_time;
    comm.data.send_data_packet.data[3] = (uint8 *)chat_packet.msg;

    comm.dev.cmd = COMM_SEND;
    pthread_mutex_lock(mutex);
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_SEND_ERR);

    comm.dev.cmd = COMM_RECV;
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_RECV_ERR);
    pthread_mutex_unlock(mutex);

    if (comm.data.recv_data_packet.ack == SHORT_OF_DATA_ACK)
        ret = FUNCAPP_SHORT_OF_DATA;
    if (comm.data.recv_data_packet.ack == CHAT_SENDACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_OWNER_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == CHAT_RECVACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_FRIEND_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == CHAT_SEND_SUCCESS_ACK)
        ret = TRUE;

    comm_core_destory(&comm);
    if (ret == TRUE)
        save_chat_history(chat_packet, 0);

    return ret;
}


/**
 * @brief	好友链表头初始化  
 * @param	friend_list_head
 * @return	void
 * @note:
 */
void friend_list_head_init(struct list_head *friend_list_head)
{
    if (!friend_list_head) {
        DEBUG("PARAM ERROR!\r\n");
        return;
    }

    init_list_head(friend_list_head);
}

/**
 * @brief	向服务器读取好友信息并写入好友链表  
 * @param	mutexfd--带互斥的socket通信fd
 *          friend_list_head--好友链表
 * @return	-FUNCAPP_PARAM_NULL_ERR     入口参数空
 *          -FUNCAPP_FD_INVALID_ERR     fd无效
 *          -FUNCAPP_SEND_ERR           发送失败
 *          -FUNCAPP_RECV_ERR           接收失败
 * 
 *          TRUE                                加载成功
 *          FUNCAPP_LOAD_FAIL                   服务器获取好友表发生错误
 *          FUNCAPP_OWNER_ACCOUNT_NOT_EXIST     用户账号不存在
 *          FUNCAPP_NO_FRIEND                   没有好友信息
 *          FUNCAPP_SHORT_OF_DATA               缺少发送信息 
 * @note:
 */
int load_friend(struct mutexfd *mutexfd, char *owner_account, 
                struct list_head *friend_list_head)
{
    int ret = 0;
    struct comm_core comm;
    struct friend_info friend_info_tmp;
    pthread_mutex_t *mutex = NULL;

    
    if (!friend_list_head || !owner_account || !mutexfd) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (strlen(owner_account) == 0) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (mutexfd->clientfd == -1) {
        DEBUG("SOCKET FD 无效！\r\n");
        return (-FUNCAPP_FD_INVALID_ERR);
    }

    mutex = &mutexfd->mutex;
    comm_core_init(&comm);
    comm.data.sendfd = mutexfd->clientfd;
    comm.data.recvfd = mutexfd->clientfd;

    comm.data.send_data_packet.cmd_type = FRIEND_CMD_TYPE;
    comm.data.send_data_packet.cmd = LOAD_FRIEND_CMD;
    comm.data.send_data_packet.data[0] = (uint8 *)owner_account;
    comm.dev.cmd = COMM_SEND;

    pthread_mutex_lock(mutex);
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_SEND_ERR);

    comm.dev.cmd = COMM_RECV;
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_RECV_ERR);

    /*服务器加载好友发生错误*/
    if (comm.data.recv_data_packet.ack == LOAD_FAIL_ACK)
        ret = FUNCAPP_LOAD_FAIL;
    if (comm.data.recv_data_packet.ack == LOAD_ACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_OWNER_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == LOAD_NO_OWNER_INFO_ACK)
        ret = FUNCAPP_NO_FRIEND;
    if (comm.data.recv_data_packet.ack == SHORT_OF_DATA_ACK)
        ret = FUNCAPP_SHORT_OF_DATA;
    if (comm.data.recv_data_packet.ack != LOAD_SENDING_ACK) {
        comm_core_destory(&comm);
        pthread_mutex_unlock(mutex);
        return ret;
    }

    do {
        friend_info_tmp.online_flag = 
                        atoi((char *)comm.data.recv_data_packet.data[0]);
        strncpy(friend_info_tmp.name,
                (char *)comm.data.recv_data_packet.data[1], NAME_MAX_LENGTH);
        strncpy(friend_info_tmp.account,
                (char *)comm.data.recv_data_packet.data[2], ACCOUNT_MAX_LENGTH);
        add_friend_to_list(friend_list_head, friend_info_tmp);
        ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    } while (comm.data.recv_data_packet.ack == LOAD_SENDING_ACK);
    pthread_mutex_unlock(mutex);

    comm_core_destory(&comm);
    return TRUE;
}

/**
 * @brief	向服务器发送添加好友信息，并将好友加入好友链表  
 * @param	owner_account--当前用户账号
 *          friend_account--好友账号
 *          friend_list_head--好友链表
 *          mutexfd--带互斥的socket通信fd
 * @return	-FUNCAPP_PARAM_NULL_ERR     入口参数空
 *          -FUNCAPP_FD_INVALID_ERR     fd无效
 *          -FUNCAPP_SEND_ERR           发送失败
 *          -FUNCAPP_RECV_ERR           接收失败
 * 
 *          TRUE                                添加成功
 *          FUNCAPP_FRIEND_IS_OWNER             好友账号就是当前账号
 *          FUNCAPP_ADD_FAIL                    服务器添加好友发生错误
 *          FUNCAPP_OWNER_ACCOUNT_NOT_EXIST     用户账号不存在
 *          FUNCAPP_FRIEND_ACCOUNT_NOT_EXIST    好友账号不存在
 *          FUNCAPP_EXCEED_FRIEND_NUM           好友数量满
 *          FUNCAPP_IS_ALREADY_FRIEND           已经添加为好友
 *          FUNCAPP_FRIEND_ADD_OWNER_FAIL       好友添加用户为好友失败
 *          FUNCAPP_SHORT_OF_DATA               缺少发送信息 
 * @note:
 */
int add_friend(char *owner_account, char *friend_account,
            struct list_head *friend_list_head, struct mutexfd *mutexfd)
{
    int ret = 0;
    struct comm_core comm;
    struct friend_info friend_info_tmp;
    pthread_mutex_t *mutex = NULL;
    
    if (!friend_list_head || !owner_account ||
        !friend_account || !mutexfd) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (strlen(owner_account) == 0 || strlen(friend_account) == 0) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (mutexfd->clientfd == -1) {
        DEBUG("SOCKET FD 无效！\r\n");
        return (-FUNCAPP_FD_INVALID_ERR);
    }
    if (!strcmp(owner_account, friend_account)) {
        return FUNCAPP_FRIEND_IS_OWNER;
    }

    mutex = &mutexfd->mutex;
    comm_core_init(&comm);
    comm.data.sendfd = mutexfd->clientfd;
    comm.data.recvfd = mutexfd->clientfd;
    comm.data.send_data_packet.cmd_type = FRIEND_CMD_TYPE;
    comm.data.send_data_packet.cmd = ADD_FRIEND_CMD;
    comm.data.send_data_packet.data[0] = (uint8 *)owner_account;
    comm.data.send_data_packet.data[1] = (uint8 *)friend_account;
    comm.dev.cmd = COMM_SEND;

    pthread_mutex_lock(mutex);
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_SEND_ERR);

    comm.dev.cmd = COMM_RECV;
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_RECV_ERR);
    pthread_mutex_unlock(mutex);

    if (comm.data.recv_data_packet.ack == SHORT_OF_DATA_ACK)
        ret = FUNCAPP_SHORT_OF_DATA;
    if (comm.data.recv_data_packet.ack == ADD_FAIL_ACK)
        ret = FUNCAPP_ADD_FAIL;
    if (comm.data.recv_data_packet.ack == ADD_OWNERACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_OWNER_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == ADD_FRIENDACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_FRIEND_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == ADD_EXCEED_FRIEND_NUM)
        ret = FUNCAPP_EXCEED_FRIEND_NUM;
    if (comm.data.recv_data_packet.ack == ADD_IS_FRIEND_ALREADY_ACK)
        ret = FUNCAPP_IS_ALREADY_FRIEND;
    if (comm.data.recv_data_packet.ack == ADD_FRIEND_ADD_OWNER_FAIL_ACK)
        ret = FUNCAPP_FRIEND_ADD_OWNER_FAIL;
    if (comm.data.recv_data_packet.ack == ADD_SUCCESS_ACK)
        ret = TRUE;

    if (ret == TRUE) {
        friend_info_tmp.online_flag = 
                        atoi((char *)comm.data.recv_data_packet.data[0]);
        strncpy(friend_info_tmp.name,
                (char *)comm.data.recv_data_packet.data[1],
                NAME_MAX_LENGTH);
        strncpy(friend_info_tmp.account, friend_account, ACCOUNT_MAX_LENGTH);
        add_friend_to_list(friend_list_head, friend_info_tmp);
    }
    
    comm_core_destory(&comm);
    return ret;
}

/**
 * @brief	向服务器发送删除好友信息，并将好友移出好友链表  
 * @param	owner_account--当前用户账号
 *          friend_account--好友账号
 *          friend_list_head--好友链表
 *          mutexfd--带互斥的socket通信fd
 * @return	-FUNCAPP_PARAM_NULL_ERR     入口参数空
 *          -FUNCAPP_FD_INVALID_ERR     fd无效
 *          -FUNCAPP_SEND_ERR           发送失败
 *          -FUNCAPP_RECV_ERR           接收失败
 * 
 *          TRUE                                删除成功
 *          FUNCAPP_FRIEND_IS_OWNER             好友账号就是当前账号
 *          FUNCAPP_REMOVE_FAIL                 服务器删除好友发生错误
 *          FUNCAPP_OWNER_ACCOUNT_NOT_EXIST     用户账号不存在
 *          FUNCAPP_FRIEND_ACCOUNT_NOT_EXIST    好友账号不存在
 *          FUNCAPP_NOT_FRIEND                  不是好友
 *          FUNCAPP_FRIEND_RMOVE_OWNER_FAIL     好友删除用户为好友失败
 *          FUNCAPP_SHORT_OF_DATA               缺少发送信息 
 * @note:
 */
int remove_friend(char *owner_account, char *friend_account,
            struct list_head *friend_list_head, struct mutexfd *mutexfd)
{
    int ret = 0;
    struct comm_core comm;
    pthread_mutex_t *mutex = NULL;
    
    if (!friend_list_head || !owner_account ||
        !friend_account || !mutexfd) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (strlen(owner_account) == 0 || strlen(friend_account) == 0) {
        DEBUG("PARAM ERROR!\r\n");
        return (-FUNCAPP_PARAM_NULL_ERR);
    }
    if (mutexfd->clientfd == -1) {
        DEBUG("SOCKET FD 无效！\r\n");
        return (-FUNCAPP_FD_INVALID_ERR);
    }
    if (!strcmp(owner_account, friend_account)) {
        return FUNCAPP_FRIEND_IS_OWNER;
    }

    mutex = &mutexfd->mutex;
    comm_core_init(&comm);
    comm.data.sendfd = mutexfd->clientfd;
    comm.data.recvfd = mutexfd->clientfd;
    comm.data.send_data_packet.cmd_type = FRIEND_CMD_TYPE;
    comm.data.send_data_packet.cmd = REMOVE_FRIEND_CMD;
    comm.data.send_data_packet.data[0] = (uint8 *)owner_account;
    comm.data.send_data_packet.data[1] = (uint8 *)friend_account;
    comm.dev.cmd = COMM_SEND;

    pthread_mutex_lock(mutex);
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_SEND_ERR);

    comm.dev.cmd = COMM_RECV;
    ret = comm.ioctl(&comm.dev, comm.dev.cmd, comm.dev.arg);
    if (ret < 0)
        return (-FUNCAPP_RECV_ERR);
    pthread_mutex_unlock(mutex);

    if (comm.data.recv_data_packet.ack == SHORT_OF_DATA_ACK)
        ret = FUNCAPP_SHORT_OF_DATA;
    if (comm.data.recv_data_packet.ack == REMOVE_FAIL_ACK)
        ret = FUNCAPP_REMOVE_FAIL;
    if (comm.data.recv_data_packet.ack == REMOVE_OWERACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_OWNER_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == REMOVE_FRIENDACCOUNT_NOT_EXIST_ACK)
        ret = FUNCAPP_FRIEND_ACCOUNT_NOT_EXIST;
    if (comm.data.recv_data_packet.ack == REMOVE_NOT_FRIEND_ACK)
        ret = FUNCAPP_NOT_FRIEND;
    if (comm.data.recv_data_packet.ack == REMOVE_FRIEND_RMOVE_OWNER_FAIL_ACK)
        ret = FUNCAPP_FRIEND_RMOVE_OWNER_FAIL;
    if (comm.data.recv_data_packet.ack == REMOVE_SUCCESS_ACK)
        ret = TRUE;

    if (ret == TRUE)
        remove_friend_from_list(friend_list_head, friend_account);
    
    return ret;
}


void destroy_friend_list(struct list_head *friend_list_head)
{   
    if (!friend_list_head) {
        DEBUG("PARAM ERROR!\r\n");
        return;
    }

    device_destroy_friend_list(friend_list_head);
}

void show_friend(struct list_head *friend_list_head)
{
     struct friend *p_friend_tmp;
     struct list_head *head, *next;

     printf("--------------------------------\r\n");
     printf("==好友表==\r\n");

     head = friend_list_head;
     list_for_each(next, head) {
        p_friend_tmp = list_entry(next, struct friend, list);
        printf("好友状态：%d\r\n", p_friend_tmp->info.online_flag);
        printf("好友昵称：%s\r\n", p_friend_tmp->info.name);
        printf("好友账号：%s\r\n", p_friend_tmp->info.account);
        printf("------------\r\n");
     }

    printf("--------------------------------\r\n");
}

